﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.Windows.Forms.DataVisualization.Charting;
using CCD_NET;

namespace HxSpec
{
    public partial class FormMain : Form
    {
        #region Variables
        public hxCCD TCD1304 = new hxCCD(0);
        public hxCCD ILX511 = new hxCCD(1);
        public hxCCD ccd = null;
        public uint ccdStatus = 0xFFFFFFFF;
        public double[] ccdWavelengthData = null;
        public double[] ccdWavenumberData = null;
        public double[] ccdPixelData = null;
        public ushort[] ccdIntensity = null;
        public ushort[][] ccdIntensityMatrix = null;
        public double[] yData = null;
        public double[] xData = null;
        private bool ReadOver = true;
        private int CurrentIndex = 0;
        private bool NeedChangeTime = false;
        private double SelectionStart = double.NaN;
        #endregion

        #region Controls
        private System.Threading.Timer TimerChart;
        private TimerCallback tcb;
        #endregion

        #region Events Callback
        //
        public FormMain()
        {
            InitializeComponent();
            InitialControl();
            InitializeTimer();
            return;
        }

        //
        private void BtnOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog OpnDialog = new OpenFileDialog();
            OpnDialog.Filter = "光谱文件(*.axb)|*.axb";
            OpnDialog.RestoreDirectory = true;
            OpnDialog.Title = "打开光谱文件...";

            if (OpnDialog.ShowDialog() == DialogResult.OK)
            {
                Stream OpnStream;
                OpnStream = OpnDialog.OpenFile();
                if (OpnStream != null)
                {
                    chartMain.Serializer.Content = System.Windows.Forms.DataVisualization.Charting.SerializationContents.All;
                    chartMain.Serializer.Load(OpnStream);
                }
            }
        }

        //
        private void BtnSave_Click(object sender, EventArgs e)
        {
            SaveFileDialog SavDialog = new SaveFileDialog();
            SavDialog.Filter = "光谱文件(*.axb)|*.axb";
            SavDialog.RestoreDirectory = true;
            SavDialog.Title = "保存光谱数据...";

            if (SavDialog.ShowDialog() == DialogResult.OK)
            {
                Stream SavStream;
                SavStream = SavDialog.OpenFile();
                if (SavStream != null)
                {
                    chartMain.Serializer.Content = System.Windows.Forms.DataVisualization.Charting.SerializationContents.All;
                    chartMain.Serializer.Save(SavStream);
                }
                SavStream.Close();
            }
        }

        //
        private void BtnSaveAs_Click(object sender, EventArgs e)
        {
            SaveFileDialog SavDialog = new SaveFileDialog();
            Stream SavStream;
            SavDialog.Filter = "文本文档 (*.txt)|*.txt|表格 (*.xls)|*.xls|图片 (*.bmp)|*.bmp";
            SavDialog.RestoreDirectory = true;
            SavDialog.Title = "另保存...";

            if (SavDialog.ShowDialog() == DialogResult.OK)
            {
                SavStream = SavDialog.OpenFile();
                if (SavStream != null)
                {
                    switch (SavDialog.FilterIndex)
                    {
                        case 1:
                            StreamWriter StreamW = new StreamWriter(SavStream);
                            for (int i = 0; i < ccd.Width; i++)
                            {
                                StreamW.Write(this.ccdPixelData[i].ToString());
                                StreamW.Write('\t');
                                StreamW.Write(this.ccdWavelengthData[i].ToString());
                                StreamW.Write('\t');
                                StreamW.Write(this.ccdWavenumberData[i].ToString());
                                StreamW.Write('\t');
                                StreamW.Write(this.ccdIntensity.ToString());
                                StreamW.Write(Environment.NewLine);
                            }
                            StreamW.Flush();
                            StreamW.Close();
                            break;
                        case 2:
                            break;
                        case 3:
                            chartMain.SaveImage(SavStream, System.Drawing.Imaging.ImageFormat.Png);
                            break;
                        default:
                            break;
                    }
                    SavStream.Close();
                    MessageBox.Show("完成！");
                }
            }
        }
        
        //
        private void BtnLink_Click(object sender, EventArgs e)
        {
            ComboBoxCCD.Enabled = false;
            BtnCalib.Enabled = true;
            BtnLink.Enabled = false;
            BtnSingle.Enabled = true;
            BtnStop.Enabled = true;
            BtnContinue.Enabled = true;
            ComboBoxFreq.Enabled = false;
            ComboBoxTime.Enabled = true;
            CurrentIndex = ComboBoxTime.SelectedIndex;
            switch (ComboBoxCCD.SelectedIndex)
            {
                case 0:
                    {
                        ccd = TCD1304;
                        break;
                    }
                case 1:
                    {
                        ccd = ILX511;
                        break;
                    }
                default:
                    break;
            }
            InitialData();
            //ccd.OpenDevice();
        }

        //
        private void BtnClose_Click(object sender, EventArgs e)
        {
            if (ccd != null)
            {
                ccd.CloseDevice();
            }
            else
            {
                MessageBox.Show("No Device Linked!");
            }
            ccdIntensity = null;
            ccdIntensityMatrix = null;
            yData = null;
            xData = null;
            ccdPixelData = null;
            ccdWavelengthData = null;
            ccdWavenumberData = null;
            TimerChart.Dispose();
            InitialControl();
        }

        //
        private void BtnContinue_Click(object sender, EventArgs e)
        {
            TimerChart.Change(0, 100);
        }

        //
        private void BtnStop_Click(object sender, EventArgs e)
        {
            TimerChart.Change(-1, 100);
        }

        //
        private void ComboBoxTime_DropDownClosed(object sender, EventArgs e)
        {
            if (ComboBoxTime.SelectedIndex == CurrentIndex)
                NeedChangeTime = false;
            else
            {
                NeedChangeTime = true;
                CurrentIndex = ComboBoxTime.SelectedIndex;
            }
        }

        //
        private delegate void UpdateUICallBack();

        //
        private void OnTimer(Object sender)
        {
            try
            {
                if (ReadOver)
                {
                    //update Data
                    ReadOver = false;
                    if (NeedChangeTime)
                    {
                        NeedChangeTime = false;
                        //ccdStatus = ccd.SetIntegralTime(CurrentIndex);
                    }
                    //ccdStatus = ccd.ReadData(ccdIntensity);
                    //dataProcess1(this.yData, this.ccdIntensity);
                    yData[100] += 1;
                    xData = ccdPixelData;
                    ReadOver = true;
                    //call UpdateUI()
                    this.Invoke(new UpdateUICallBack(UpdateUI));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region Methods - Initial and Update
        private void InitialControl()
        {
            BtnCalib.Enabled = false;
            BtnLink.Enabled = true;
            BtnSingle.Enabled = false;
            BtnStop.Enabled = false;
            BtnContinue.Enabled = false;
            ComboBoxFreq.Enabled = false;
            ComboBoxTime.Enabled = false;
            ComboBoxCCD.SelectedIndex = 0;
        }
        private void InitialData()
        {
            if (ccd != null)
            {
                this.ccdPixelData = new double[ccd.Width];
                this.ccdWavelengthData = new double[ccd.Width];
                this.ccdWavenumberData = new double[ccd.Width];
                this.ccdIntensity = new ushort[ccd.Width];
                this.yData = new double[ccd.Width];
                this.xData = new double[ccd.Width];
                this.ccdIntensityMatrix = new ushort[100][];
                for (int i = 0; i < 100; i++)
                {
                    this.ccdIntensityMatrix[i] = new ushort[ccd.Width];
                    for (int j = 0; j < ccd.Width; j++)
                        this.ccdIntensityMatrix[i][j] = 0;
                }
                for (int i = 0; i < ccd.Width; i++)
                {
                    this.ccdPixelData[i] = i;
                    this.ccdWavelengthData[i] = 0;
                    this.ccdWavenumberData[i] = 0;
                    this.ccdIntensity[i] = 0;
                    //this.yData[i] = 0;
                    //this.xData[i] = i;
                }
            }
            else
                MessageBox.Show("No Device Linked!");
        }
        private void InitializeTimer()
        {
            tcb = this.OnTimer;
            TimerChart = new System.Threading.Timer(tcb, null, Timeout.Infinite, 50);
        }
        private void InitialChart()
        {
            chartMain.Series[0].Points.DataBindXY(xData, yData);
        }
        private void UpdateUI()
        {
            toolStripStatusLabel1.Text = ccdIntensity[100].ToString();
            chartMain.Series[0].Points.DataBindXY(xData, yData);
        }
        #endregion

        #region Methods - Spectrum
        public void dataProcess1(double[] YdataOut, ushort[] Ydata)
        {
            for (int i = 0; i < Ydata.Length; i++)
            {
                YdataOut[i] = Ydata[i];
            }
        }
        public void getWavelengthInNM(double[] XdataOut, double[] Xdata, double[] a, int order)
        {
            double sum;
            for (int i = 0; i < Xdata.Length; i++)
            {
                sum = 0;
                for (int j = 0; j < order; j++)
                {
                    sum += a[j] * Math.Pow(Xdata[i], j);
                }
                XdataOut[i] = sum;
            }
        }
        public void getWavenumberInCM(double[] XdataOut, double[] Xdata, double[] a, int order, double laser)
        {
            double sum;
            for (int i = 0; i < Xdata.Length; i++)
            {
                sum = 0;
                for (int j = 0; j < order; j++)
                {
                    sum += a[j] * Math.Pow(Xdata[i], j);
                }
                XdataOut[i] = 10000000*(1/laser-1/sum);
            }
        }
        #endregion

        #region Methods - Chart
        //
        private void AddTextAnnotation(DataPoint DP)
        {
            TextAnnotation annotation = new TextAnnotation();
            annotation.AnchorDataPoint = DP;// chartMain.Series[0].Points[2];
            annotation.Text = "x:" + DP.XValue.ToString();// +"y:" + DP.YValues[0].ToString();
            annotation.ForeColor = Color.Red;
            annotation.Font = new Font("Arial", 12);
            annotation.Visible = true;

            chartMain.Annotations.Add(annotation);
        }
        
        //
        private int FindNearestDataPoint(double X)
        {
            // Get the int portion of the X value
            int curIndex = 0;// = (int)Math.Round(X);
            int i;
            for (i = 0; i < ccd.Width; i++)
            {
                if ((X >= chartMain.Series[0].Points[i].XValue) && (X <= chartMain.Series[0].Points[i + 1].XValue))
                {
                    if ((X - chartMain.Series[0].Points[i].XValue) <= (chartMain.Series[0].Points[i + 1].XValue - X))
                    {
                        curIndex = i;
                    }
                    else
                    {
                        curIndex = i + 1;
                    }
                }
            }

            // If curIndex is less than 1 curIndex is set to 1
            curIndex = (int)Math.Max(curIndex, 0);

            // If curIndex is greater than 5 curIndex is set to 5 (X Value of max point in series)
            curIndex = (int)Math.Min(curIndex, ccd.Width - 1);

            // Return the point value of the nearest point
            return curIndex;
        }

        //Cursor Action with Key
        protected override bool ProcessDialogKey(Keys keyData)
        {
            // Avoid dialog processing of arrow keys
            if (keyData == Keys.Left || keyData == Keys.Right)
            {
                return false;
            }
            return base.ProcessDialogKey(keyData);
        }

        //
        private void ProcessSelect(System.Windows.Forms.KeyEventArgs e)
        {
            // Process keyboard keys
            if (e.KeyCode == Keys.Right)
            {
                // Make sure the selection start value is assigned
                if (this.SelectionStart == double.NaN)
                    this.SelectionStart = chartMain.ChartAreas[0].CursorX.Position;

                // Set the new cursor position 
                chartMain.ChartAreas[0].CursorX.Position += 1;
            }
            else if (e.KeyCode == Keys.Left)
            {
                // Make sure the selection start value is assigned
                if (this.SelectionStart == double.NaN)
                    this.SelectionStart = chartMain.ChartAreas[0].CursorX.Position;

                // Set the new cursor position 
                chartMain.ChartAreas[0].CursorX.Position -= 1;
            }

            // If the cursor is outside the view, set the view
            // so that the cursor can be seen
            SetView();


            chartMain.ChartAreas[0].CursorX.SelectionStart = this.SelectionStart;
            chartMain.ChartAreas[0].CursorX.SelectionEnd = chartMain.ChartAreas[0].CursorX.Position;
        }

        //
        private void SetView()
        {
            // Keep the cursor from leaving the max and min axis points
            if (chartMain.ChartAreas[0].CursorX.Position < 0)
                chartMain.ChartAreas[0].CursorX.Position = 0;

            else if (chartMain.ChartAreas[0].CursorX.Position > ccd.Width - 1)
                chartMain.ChartAreas[0].CursorX.Position = ccd.Width - 1;


            // Move the view to keep the cursor visible
            if (chartMain.ChartAreas[0].CursorX.Position < chartMain.ChartAreas[0].AxisX.ScaleView.Position)
                chartMain.ChartAreas[0].AxisX.ScaleView.Position = chartMain.ChartAreas[0].CursorX.Position;

            else if ((chartMain.ChartAreas[0].CursorX.Position >
                (chartMain.ChartAreas[0].AxisX.ScaleView.Position + chartMain.ChartAreas[0].AxisX.ScaleView.Size)))
            {
                chartMain.ChartAreas[0].AxisX.ScaleView.Position =
                    (chartMain.ChartAreas[0].CursorX.Position - chartMain.ChartAreas[0].AxisX.ScaleView.Size);
            }
        }

        //
        private void ProcessScroll(System.Windows.Forms.KeyEventArgs e)
        {
            // Process keyboard keys
            if (e.KeyCode == Keys.Right)
                // set the new cursor position 
                chartMain.ChartAreas[0].CursorX.Position += 1;

            else if (e.KeyCode == Keys.Left)
                // Set the new cursor position 
                chartMain.ChartAreas[0].CursorX.Position -= 1;

            // If the cursor is outside the view, set the view
            // so that the cursor can be seen
            SetView();


            // Set the selection start variable in case shift arrows are selected
            this.SelectionStart = chartMain.ChartAreas[0].CursorX.Position;

            // Reset the old selection start and end
            chartMain.ChartAreas[0].CursorX.SelectionStart = double.NaN;
            chartMain.ChartAreas[0].CursorX.SelectionEnd = double.NaN;
        }

        #endregion
    }
}
